/**
 * 
 */
package hu.gbalage.owlforms.impl;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.semanticweb.owl.inference.OWLReasonerException;
import org.semanticweb.owl.model.OWLClass;
import org.semanticweb.owl.model.OWLDataRange;
import org.semanticweb.owl.model.OWLDataType;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLEntity;
import org.semanticweb.owl.model.OWLObjectUnionOf;
import org.semanticweb.owl.model.OWLProperty;

import hu.gbalage.owlforms.OWLFormsConstants;
import hu.gbalage.owlforms.OWLFormsManager;
import hu.gbalage.owlforms.api.ComplexField;
import hu.gbalage.owlforms.api.Entity;
import hu.gbalage.owlforms.api.FieldCardinality;
import hu.gbalage.owlforms.api.Form;
import hu.gbalage.owlforms.internal.AnnotationCollector;

/**
 * @author Grill Balazs (balage.g@gmail.com)
 *
 */
public class FieldImpl implements ComplexField {

	private final Form form;
	private final OWLProperty<?,?> property;
	
	private final Set<URI> range = new HashSet<URI>();
	
	private final List<Form> contained = new ArrayList<Form>();
	
	private final AnnotationCollector collector;
	
	private final OWLFormsManager manager;
	
	private boolean hasGeneratedValue(OWLProperty<?,?> property){
		return collector.collect(property, OWLFormsConstants.ANNOTATION_DERIVATIVE).size() > 0;
	}
	
	public FieldImpl(OWLFormsManager manager, Form form, OWLProperty<?,?> property) throws OWLReasonerException{
		this.form = form;
		this.property = property;
		this.manager = manager;
		this.collector = new AnnotationCollector(manager);
		
		collector.logAnnotations(property);
		
		manager.getLog().debug("Ranges for property: "+property.getURI());
		if (property.isOWLDataProperty()){
			Set<OWLDataRange> ranges = manager.getReasoner().getRanges(property.asOWLDataProperty());
			for(OWLDataRange r : ranges){
				if (r.isDataType()){
					range.add(((OWLDataType)r).getURI());
				}
			}
		}else
		for(Object o : property.getRanges(manager.listOntologies())){
			if (o instanceof OWLEntity){
				OWLEntity e = (OWLEntity)o;
				manager.getLog().debug("Range entity: "+e.getURI());
				range.add(e.getURI());
			}if (o instanceof OWLObjectUnionOf){
				OWLObjectUnionOf union = (OWLObjectUnionOf)o;
				manager.getLog().debug("Range union:");
				for(OWLDescription desc : union.getOperands()){
					if (!desc.isAnonymous()){
						manager.getLog().debug("  "+desc.asOWLClass().getURI());
						range.add(desc.asOWLClass().getURI());
					}
				}
			}else{
				manager.getLog().error("Could not process range of property "+property.getURI()+": "+o.getClass());
			}
		}
		
		if (property.isOWLDataProperty()){
			//contained = null;
		}else{
			for(URI r : range){
				OWLClass clazz = manager.getDataFactory().getOWLClass(r);
				contained.add(new FormImpl(manager,clazz));
			}
			//contained = new FormImpl(manager,clazz);
		}
	}
	
	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.api.Field#getAcceptedTypes()
	 */
	public Set<URI> getAcceptedTypes() {
		return range;
	}

	private FieldCardinality cardinality = null;
	
	public void setCardinality(FieldCardinality cardinality){
		this.cardinality = cardinality;
	}
	
	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.api.Field#getCardinality()
	 */
	public FieldCardinality getCardinality() {
		return cardinality;
	}

	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.api.Field#getForm()
	 */
	public Form getForm() {
		return form;
	}

	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.api.Field#isPrimitive()
	 */
	public boolean isPrimitive() {
		return property.isOWLDataProperty();
	}

	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.api.Entity#getURI()
	 */
	public URI getURI() {
		return property.getURI();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Entity) 
			return getURI().equals(((Entity)obj).getURI());
		return super.equals(obj);
	}
	
	public boolean isComplex() {
		return property.isOWLObjectProperty();
	}
	
	public ComplexField asComplexField() {
		if (isComplex()) return this;
		return null;
	}
	
	public Form[] getContainedForm() {
		return contained.toArray(new Form[]{}); //support for polymorphism
	}

	public boolean isDerivative() {
		return hasGeneratedValue(property);
	}
	
	public boolean isImported() {
		boolean imported = collector.collect(property, OWLFormsConstants.ANNOTATION_IMPORTED).size() > 0;
		manager.getLog().debug("Check imported: "+property.getURI()+" - "+imported);
		return imported;
	}
	
}
